Thread: [Query]How to store a name with space in-between?

  1. #1
    Registered User
    Join Date
    Dec 2014
    Posts
    1

    [Query]How to store a name with space in-between?

    Program used: Dev C++ Version 5.7.1 Build time: July 29 2014 - 23:53, at Windows 8.
    compiler set to configure: TDM-GCC 4.8.1 64-bit release

    I'm a first year student in computer engineering(undergraduate), have had my hands on C for the past 2/3months. Technically, sometimes I don't even understand what I'd typed and if it's valid or not.
    The below is a homework given by my lecturer. I managed to type it, but I hope to learn if there's any better way to get the name which scanf wouldn't run through as it stops at white space. And I used pointer(or is it not?) to make it one part only alphabets and the other one digits. I'd like to know if there's better practice. I'm sorry to admit that I'm still new to this area and would really want to learn more, thanks.

    The coding, calculate_charges.c and the open file, customer.txt are attached at the end of the post.
    Code:
    #include <stdio.h>
    #include <string.h>
    #define SIZE 3
    void trimback(char input[], int strnameindex);
    void trimfrnt(char input[], int strnameindex);
    float calculate_charge (float time_start, float total_hour);
    float average_charge (float total_charge, float total_hour);
    int main()
    {
     FILE *fileread, *filewrite;
     int namesize, len;
     int i, str_i, str_nameindex[SIZE] = {0};
     float time_start[SIZE], total_hour[SIZE], total_charge[SIZE], charge_per_hour[SIZE];
     char name[SIZE][9], input[SIZE][50], namebuffer[SIZE][50];
    //1openfile 
     fileread = fopen("customer.txt", "r");
     
     for(i=0; fgets(input[i], 50, fileread) != NULL; i++)
     {
      for(str_i = 0; !isdigit(input[i][str_i]) ; str_i++)
      {
       str_nameindex[i]++;
      }
      
      strcpy(namebuffer[i], input[i]);
      trimback(namebuffer[i], str_nameindex[i]);
      strcpy(name[i], namebuffer[i]);
      
      trimfrnt(input[i], str_nameindex[i]);
      sscanf(input[i], "%f %f", &time_start[i], &total_hour[i]);
     }
     fclose (fileread);
    //0openfile
    //1calculation
     for (i=0; i<SIZE ; i++)
     {
      total_charge[i] = calculate_charge(time_start[i], total_hour[i]);
      charge_per_hour[i] = average_charge(total_charge[i], total_hour[i]);
     }
    //0calculation
     
    //1savefile 
     filewrite = fopen("charges.txt", "w");
     
     fprintf(filewrite, "Name        total charge     charge per hour\n");
     for(i=0; i<SIZE ; i++)
     {
      fprintf(filewrite, "%-12sRM%-15.2fRM%.2f\n", name[i], total_charge[i], charge_per_hour[i]);
     }
     
     fclose (filewrite);
    //0savefile
     return 0;
    }
    void trimback(char input[], int strnameindex)
    {
     char *ary;
     int i;
     int len;
     len = strlen(input);
     ary = input;
     *(ary + i + strnameindex) = *(ary + len);
    }
    void trimfrnt(char input[], int strnameindex)
    {
     char *ary;
     int i;
     int len;
     len = strlen(input);
     ary = input;
     
     for(i=0; i<len; i++)
      *(ary + i) = *(ary + i + strnameindex);
    }
    float calculate_charge (float time_start, float total_hour)
    {
     float total_charge;
     if(time_start >= 9.00 && time_start<= 21.00)
     {
      if(total_hour * 100 - 1000 <= 0)
      {
       total_charge = 9.50;
      }
      
      else if(total_hour * 100 - 1000 > 0)
      {
       total_charge = 9.50 + ((int)total_hour-10+1)*1.50;
      }
     }
     
     else
     {
      if(total_hour * 100 - 1000 <= 0)
      {
       total_charge = 9.50;
       total_charge *= 0.9;
      }
      
      else if(total_hour * 100 - 1000 > 0)
      {
       total_charge = 9.50 + ((int)total_hour-10+1)*1.50;
       total_charge *= 0.9;
      }
     }
     return total_charge;
    }
    float average_charge (float total_charge, float total_hour)
    {
     float average_charge;
     average_charge = total_charge / total_hour;
     return average_charge;
    }
    Code:
    customer.txt
    Ahmad 09.00 4.2
    Mei Lin 13.00 12.5
    Julia 22.30 14.5
    Attachment 13791
    Attachment 13792
    Last edited by cmc0912; 12-02-2014 at 06:18 AM.

  2. #2
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    Check your compiler warnings. If you don't see these warnings, you need to increase the warnings emitted by the compiler (see the documentation for your compiler on how to do this).

    Code:
    /*
    main.c||In function 'main':|
    main.c|20|warning: implicit declaration of function 'isdigit'|
    main.c|11|warning: unused variable 'len'|
    main.c|11|warning: unused variable 'namesize'|
    main.c||In function 'trimback':|
    main.c|62|warning: 'i' is used uninitialized in this function|
    ||=== Build finished: 0 errors, 4 warnings ===|
    */
    You need to include "ctype.h" to use "isdigit()". The use of an uninitialized variable also needs to be addressed.

    Regarding your question, "scanf()" is not the preferred method of getting a line of text from the user. It takes some complicated hoo-doo to read a string with spaces, and it's not easy to flexibly limit the number of characters read in.

    Using "fgets()" is preferred. Be aware that "fgets()" stores the newline at the end of the string, assuming there is room. This usually has to be checked for and handled if it is present.

    FAQ > Get a line of text from the user/keyboard (C) - Cprogramming.com

    I'm a little confused, however, since you appear to be using "fgets()" in your program to read a string and not "scanf()".

    A few other notes:

    • You are using consistent indentation, which is good. I would suggest using more than a single space for indentation, however. Anywhere from 3 to 5 spaces is typical (I personally use 4).
    • Most of your variables have meaningful and descriptive names, which is also very good.
    • You should check that your files have opened successfully before trying to access them ("fopen()" returns NULL on failure).
    • Use named constants in lieu of magic numbers. You #define a constant called SIZE which is good. But you still have magic numbers in your program (for instance, 50 in your "fgets()" call).


    I haven't really dug deep into your program, but these are the things I saw after a quick review.

    Technically, sometimes I don't even understand what I'd typed and if it's valid or not.
    This means you're moving ahead too quickly. I'd recommend spending more time on previous topics until they make sense. Manually type in all examples and run them, alter the examples a little bit to see if the changes you make give the expected results, and make little practice programs yourself based on the current material. Familiarize yourself with the concepts. As you progress, you want to make sure you understand exactly what each and every line of code is doing.

    You should figure out how you best learn programming concepts (for instance, I learn best by hand-writing notes for each concept - the hand-written notes are of little use to me after, but for some reason the act of writing them down solidifies the concepts in my mind). We all learn differently, so you need to discover how you best learn programming languages in general. Especially considering that you will probably be learning other languages as part of your curriculum.

  3. #3
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    A compact way would be:
    Code:
    char name[100];
    scanf("%[^\n]", name);
    The above will grab any and all characters excluding the newline on all *nix platforms. On Windows, Mac or other OSes this may need to be changed depending on their definition of the line separator.
    Last edited by itCbitC; 12-02-2014 at 11:04 AM.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by itCbitC
    A compact way would be:
    Unfortunately, it would also be wrong: the field width must be specified to avoid buffer overflow, e.g.,
    Code:
    char name[100];
    if (scanf("%99[^\n]", name) == 1)
    But if you want to "flexibly limit the number of characters", i.e., not hard code the "99", then you end up with something no longer quite as compact. It would be easier to just use fgets and remove the trailing newline if necessary.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. NUMA Virtual Adress Space / Physical Adress Space
    By NUMA Orly in forum Windows Programming
    Replies: 0
    Last Post: 03-14-2011, 03:19 AM
  2. store data from ifstream and store in link list
    By peter_hii in forum C++ Programming
    Replies: 2
    Last Post: 10-26-2006, 08:50 AM
  3. DNS Query
    By Simpsonia in forum Networking/Device Communication
    Replies: 1
    Last Post: 04-24-2006, 12:42 AM
  4. Do you store store one off data arrays in a class?
    By blood.angel in forum C++ Programming
    Replies: 5
    Last Post: 06-24-2002, 12:05 PM
  5. How to store all the input char into text include space ?
    By Unregistered in forum C Programming
    Replies: 7
    Last Post: 12-20-2001, 04:34 PM